﻿define([
    'Wjs/ui/widgets/Grid'
],
function () {
    'use strict';

    var Grid = Wjs.getType('Grid'),
        GridBodyCell = Wjs.getType('GridBodyCell'), // To extend it by the CalendarCell
        ViewSingleContainer = Wjs.getType('ViewSingleContainer'),
        View = Wjs.getType('View'),
        MultipleContainer = Wjs.getType('MultipleContainer'),
        getTimeLabel,
        WeekCalendarCell,
        CalendarEvent,
        WeekCalendar = Wjs.defineOnce({

            type: 'WeekCalendar',

            internal: {

                base: Grid,

                onBeforeTypeDefined: function () {

                    getTimeLabel = function (i) {

                        if (i % 2 == 1) {
                            return '';
                        }

                        switch (i) {
                            case 0: return '12am';
                            case 2: return '1am';
                            case 4: return '2am';
                            case 6: return '3am';
                            case 8: return '4am';
                            case 10: return '5am';
                            case 12: return '6am';
                            case 14: return '7am';
                            case 16: return '8am';
                            case 18: return '9am';
                            case 20: return '10am';
                            case 22: return '11am';
                            case 24: return '12pm';
                            case 26: return '1pm';
                            case 28: return '2pm';
                            case 30: return '3pm';
                            case 32: return '4pm';
                            case 34: return '5pm';
                            case 36: return '6pm';
                            case 38: return '7pm';
                            case 40: return '8pm';
                            case 42: return '9pm';
                            case 44: return '10pm';
                            case 46: return '11pm';

                            default: throw 'Not implemented';
                        }

                    };

                    WeekCalendarCell = Wjs.define({

                        type: 'WeekCalendarCell',

                        internal: {

                            base: ViewSingleContainer
                        },

                        tag: 'td',

                        'class': 'wjs-week-calendar-cell',

                        setEvent: function (event) {

                            var child = this.setChild({
                                child: event
                            }, 'CalendarEvent');

                            child.adjustHeight();

                            return child;
                        }
                    });

                    // Element that overlays on top of the calendar cell
                    CalendarEvent = Wjs.define({

                        type: 'CalendarEvent',

                        internal: {

                            base: ViewSingleContainer,

                            initialize: function (cfg, parent) {

                                this.setChild(cfg.title);

                                this.event = cfg;
                            }
                        },

                        'class': 'wjs-calendar-event',

                        adjustHeight: function () {
                            var cell = this.parent,
                                slotLength = 30, // How many minutes a division (slot) has
                                intervals = Math.floor(this.event.end.getTime() - this.event.start.getTime()) / (1000 * 60 * slotLength); // The time difference in minutes

                            this.setHeight(cell.getHeight() * intervals);
                        },
                    });
                },

                construct: function (cfg, parent) {
                    var date = cfg.date || new Date(),
                        dayOfWeek = date.getDay();

                    WeekCalendar.base.constructor.call(this, cfg, parent);

                    // Calculate the first date of the week
                    this.fromDate = new Date(date);

                    if (dayOfWeek > 0) {
                        this.fromDate.setDate(date.getDate() - dayOfWeek);
                    }

                    this.events = []; // The array of event elements
                },

                initialize: function (cfg, parent) {
                    var i = 0,
                        length = 48, // Half hour slots
                        timeLabel,
                        date,
                        time,
                        columns = [],
                        weekDays = [
                            'sunday',
                            'monday',
                            'tuesday',
                            'wednesday',
                            'thursday',
                            'friday',
                            'saturday'
                        ];

                    columns.push({
                        text: '',
                        field: 'time',
                        render: function (value) {
                            return value.label; // Customize rendering the cell
                        },
                        width: 50
                    });

                    for (i = 0; i < 7; ++i) {

                        date = new Date(this.fromDate);
                        date.setDate(this.fromDate.getDate() + i);

                        columns.push({
                            date: date,
                            text: this.formatDate(date, i),
                            field: weekDays[i],
                            width: 50
                        });
                    }

                    this.createColumns({
                        columns: columns
                    });

                    this.body.defaultBodyCellType = 'WeekCalendarCell';

                    for (i = 0; i < length; ++i) {

                        this.addRow({
                            time: {
                                label: getTimeLabel(i),
                                hour: Math.floor(i / 2),
                                minutes: i % 2 === 0 ? 0 : 30
                            },
                            sunday: '',
                            monday: '',
                            tuesday: '',
                            wednesday: '',
                            thursday: '',
                            friday: '',
                            saturday: ''
                        });
                    }

                    // Now that we have the elements in place, set any event if provided
                    this.eventsCfg = cfg.events;
                }

            },

            'class': 'wjs-calendar',

            formatDate: function (date, i) {
                var weekDays = [
                    'Sun',
                    'Mon',
                    'Tue',
                    'Wed',
                    'Thu',
                    'Fri',
                    'Sat'
                ];

                return weekDays[i] + ' ' + (date.getMonth() + 1) + '/' + date.getDate();
            },

            setEvents: function (events) {
                var event,
                    length,
                    i;

                if (events) {

                    length = events.length;

                    for (i = 0; i < length; ++i) {

                        event = events[i];
                        this.setEvent(event);
                    }
                }
            },

            setEvent: function (event) {
                var column = this.getColumn(event),
                    startCell = this.getStartCell(event, column),
                    child = startCell.setEvent(event); // Create the child element

                this.events.push(child);

                return child;
            },

            //#region Helper methods

            // Retrieves the column that corresponds tothe event
            getColumn: function (event) {
                var columns = this.columns,
                    length = columns.length,
                    column,
                    date,
                    startDate = event.start,
                    i;

                for (i = 0; i < length; ++i) {

                    column = columns[i];
                    date = column.date;

                    if (!date) {
                        continue; // Not a date column
                    }

                    if (date.getDate() == startDate.getDate() &&
                        date.getMonth() == startDate.getMonth() &&
                        date.getFullYear() == startDate.getFullYear()) {

                        return column;
                    }
                }

                return null;
            },

            // Returns the starting grid row of the event
            getStartRow: function (event) {
                var rows = this.getRows(),
                    length = rows.length,
                    row,
                    time,
                    startDate = event.start,
                    i;

                for (i = 0; i < length; ++i) {

                    row = rows[i];
                    time = row.record.time;

                    if (startDate.getHours() === time.hour &&
                        Math.abs(startDate.getMinutes() - time.minutes) < 30) { // Interval

                        return row; // The row variable already has the value
                    }
                }

                return null;
            },

            // Returns the starting grid cell of the event
            getStartCell: function (event, column) {
                var row = this.getStartRow(event),
                    cells = row.getCells(),
                    length = cells.length,
                    cell,
                    i;

                for (i = 0; i < length; ++i) {

                    cell = cells[i];

                    if (cell.column == column) {
                        return cell;
                    }
                }

                return null;
            },

            //#endregion

            itemsRenderedHandler: function () {

                if (this.eventsCfg) {

                    Wjs.delay(function () {

                        this.setEvents(this.eventsCfg);

                        delete this.eventsCfg;

                    }, 0, this);
                }
            }

        });

    return WeekCalendar;
});